package com.katsu.myapplib.http;

import android.annotation.TargetApi;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Build;
import android.util.Log;

import com.katsu.myapplib.app.AppApplication;
import com.katsu.myapplib.sign.f;
import com.katsu.myapplib.sign.z;

import com.katsu.myapplib.activity.ActivityStack;
import com.katsu.myapplib.util.UtilClassName;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.Proxy;
import java.net.SocketTimeoutException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;


import okhttp3.Cache;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.OkHttpClient.Builder;
import okhttp3.Request;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.BufferedSink;
import okio.GzipSink;
import okio.Okio;
import timber.log.Timber;

/**
 * @author zhuchaoxu
 */
@f
@z
public final class Http implements DialogInterface.OnCancelListener {

    private OnStartEndCreateDialog f;

    private OkHttpClient q;

    private boolean d;

    private Context c;

    private Builder b;

    private Dialog dl;

    public static Http getInstance() {

        return h.a;

    }
    //这里是创建一个SSLSocketFactory,提供给上面的 .sslSocketFactory()
    private SSLSocketFactory createSSLSocketFactory() {
        SSLSocketFactory ssfFactory = null;
        try {
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[]{new TrustAllCerts()}, new SecureRandom());
            ssfFactory = sc.getSocketFactory();
        } catch (Exception e) {
        }

        return ssfFactory;
    }
    public class TrustAllCerts implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }


    private Http() {

        b = new OkHttpClient.Builder();
//        b.addInterceptor(new ChuckerInterceptor(AppApplication.INSTANCE)); //TODO 抓包

        //        b.sslSocketFactory( SSLSocketClient.getSSLSocketFactory());
        //        b.hostnameVerifier( SSLSocketClient.getHostnameVerifier());
        b.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }


        });
//        b.sslSocketFactory(createSSLSocketFactory();
        b.sslSocketFactory(createSSLSocketFactory(), new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        });
        b.proxy(Proxy.NO_PROXY);

        setOnStartEndCreateDialog(new OnStartEndCreateDialog<WaitDialog>() {

            @Override
            public void show(WaitDialog d) throws Exception {

                d.show();

            }

            @Override
            public void dismiss(WaitDialog d) throws Exception {

                d.dismiss();

            }

            @Override
            public WaitDialog create(Context c) throws Exception {

                return new WaitDialog(c);

            }

            @Override
            public ProgressDialog createProgressDialog() {

                return new ProgressDialog<WaitDialog>() {

                    @Override
                    public void show(WaitDialog d) {

                        d.show();

                    }

                    @Override
                    public void dismiss(WaitDialog d) {

                        d.dismiss();

                    }

                    @Override
                    public WaitDialog create(Context c) {

                        return new WaitDialog(c);

                    }

                    @Override
                    public void progress(WaitDialog d, long t, long c, int p) {

                        d.percentage(p);

                    }

                };

            }

        });

    }

    public void allTimeout(int time) {

        connectTimeout(time);

        writeTimeout(time);

        readTimeout(time);

    }

    public void connectTimeout(int time) {

        b.connectTimeout(time, TimeUnit.SECONDS);

    }

    public void writeTimeout(int time) {

        b.writeTimeout(time, TimeUnit.SECONDS);

    }

    public void readTimeout(int time) {

        b.readTimeout(time, TimeUnit.SECONDS);

    }

    public void setCache(String a, int m) {

        b.cache(new Cache(new File(a), m));

    }

    public void setCertificates(InputStream[] certificates, InputStream bksFile, String password, String type) {

        SSLParams s = HttpCert.getSslSocketFactory(certificates, bksFile, password, type);

        b.sslSocketFactory(s.sSLSocketFactory, s.trustManager);

    }

    @TargetApi(Build.VERSION_CODES.CUPCAKE)
    synchronized void g(final Context c, final boolean i, final int t, final Object e, final Asy s) {

        if (g.a(this)) {

            if (q == null) {

                q = b.build();

            }

            new AsyncTask<Void, Void, Object>() {

                private a a = s.getClass().getAnnotation(HttpGZIP.class).value() ? new a() : null;

                private HttpTimeout j = s.getClass().getAnnotation(HttpTimeout.class);

                private HttpNew w = s.getClass().getAnnotation(HttpNew.class);

                private String n = UtilClassName.getActionName(s.getClass());

                @Override
                protected void onPreExecute() {

                    try {

                        f.i(s);

                    } catch (Exception e) {

                        e.printStackTrace();

                    }

                    try {

                        if (i) {

                            show(c, s);

                        }

                    } catch (Exception e) {

                        e.printStackTrace();

                    }

                    try {

                        if (t == s.ASY_WAIT) {

                            AsyViewLayout.g(c, n, AsyViewLayout.u, null);

                        }

                    } catch (Exception e) {

                        e.printStackTrace();

                    }

                    try {

                        s.a.onStart(t, e);

                    } catch (Exception e) {

                        e.printStackTrace();

                    }

                    s.pd = f.d;

                    s.dl = dl;

                }

                @Override
                protected Object doInBackground(Void... params) {

                    try {

                        OkHttpClient o = q;

                        if (j != null || a != null || b != null || w.value()) {

                            Builder l = q.newBuilder();

                            if (j != null) {

                                l.connectTimeout(j.connect(), TimeUnit.SECONDS);

                                l.writeTimeout(j.write(), TimeUnit.SECONDS);

                                l.readTimeout(j.read(), TimeUnit.SECONDS);

                            }

                            if (a != null) {

                                l.addInterceptor(a);

                            }

                            o = l.build();

                        }

                        s.operation();

                        Response r = o.newCall(s.b()).execute();

                        int co = r.code();

                        log(s.getClass() + "->code: %s", co + "");

                        if (s.code(r.isSuccessful(), co)) {

                            c();

                            return s.s.parser(r);

                        } else {

                            s.s.TOAST = "服务器连接异常";

                        }

                    } catch (SocketTimeoutException e) {

                        s.s.TOAST = "网络连接超时";

                        e.printStackTrace();

                    } catch (Exception e) {

                        s.s.TOAST = "网络请求异常";

                        e.printStackTrace();

                    }

                    c();

                    return null;

                }

                @Override
                protected void onPostExecute(Object o) {

                    if (o == null) {

                        log(s.getClass() + "->result: %s", "onFail()");

                        try {

                            AsyViewLayout.g(c, n, r, null);

                        } catch (Exception e) {

                            e.printStackTrace();

                        }

                        try {

                            s.a.onFail(s.TOAST, t, e);

                        } catch (Exception e) {

                            e.printStackTrace();

                        }

                    } else {

                        log(s.getClass() + "->result: %s", "onSuccess()");

                        try {

                            AsyViewLayout.g(c, n, AsyViewLayout.s, null);

                        } catch (Exception e) {

                            e.printStackTrace();

                        }

                        try {

                            s.a.onSuccess(s.TOAST, t, e, o);

                        } catch (Exception e) {

                            e.printStackTrace();

                        }

                    }

                    log(s.getClass() + "->result: %s", "onEnd()");

                    try {

                        s.a.onEnd(s.TOAST, t, e);

                    } catch (Exception e) {

                        e.printStackTrace();

                    }

                    try {

                        if (i) {

                            dismiss();

                        }

                    } catch (Exception e) {

                        e.printStackTrace();

                    }

                    try {

                        p.e().d(n).u(s);

                    } catch (Exception e) {
                    }

                }

                private void c() {

                    if (s instanceof AsyPostForm) {

                        s.c();

                    }

                }

            }.execute();

        }

    }

    public synchronized void show() {

        try {

            show(ActivityStack.getTopActivity());

        } catch (Exception e) {
        }

    }

    public synchronized void show(Context context) {

        show(context, null);

    }

    private synchronized void show(Context context, Asy a) {

        boolean h = false;

        try {

            h = a.v != null;

        } catch (Exception e) {
        }

        try {

            if (!h && dl != null && c == context) {

                if (!dl.isShowing()) {

                    dismiss();

                    f.show(dl);

                }

            } else {

                try {

                    dismiss();

                    if (h) {

                        f.d.show(dl = f.d.create(c = context));

                    } else {

                        f.show(dl = f.create(c = context));

                    }

                    dl.setOnCancelListener(this);

                } catch (Exception e) {

                    c = context;

                }

            }

        } catch (Exception e) {

            dismiss();

        }

    }

    public synchronized void dismiss() {

        try {

            f.dismiss(dl);

        } catch (Exception n) {

            try {

                f.d.dismiss(dl);

            } catch (Exception nn) {
            }

        }

    }

    public synchronized String elog(String t, String m) {

        if (!hh.c() && d) {

            Log.e(t, m);

        }

        return m;

    }

    public synchronized String log(String t, String m) {

        if (!hh.c() && d) {

            Timber.e(t, m);

        }

        return m;

    }

    public synchronized void logSkip(String t, Class<?> c) {

        if (!hh.c() && d) {

            Timber.e(t, "(" + UtilClassName.getName(c) + ".java:0)");

        }

    }

    public void setIsLog(boolean isLog) {

        this.d = isLog;

    }

    public void setOnStartEndCreateDialog(OnStartEndCreateDialog onStartEndCreateDialog) {

        this.f = onStartEndCreateDialog;

    }

    public void cancelConn() {

        try {

            if (f.a.getClass().getAnnotation(HttpFinish.class).value()) {

                AppApplication.INSTANCE.finishActivity();

            } else {

                AsyViewLayout.g(c, UtilClassName.getActionName(f.a.getClass()), r, null);

            }

            q.dispatcher().cancelAll();

            log(f.a.getClass() + "->cancel: %s", "cancelConn()");

        } catch (Exception e) {
        }

    }

    @Override
    public void onCancel(DialogInterface i) {

        cancelConn();

    }

    private class a implements Interceptor {

        @Override
        public Response intercept(Chain c) throws IOException {

            Request r = c.request();

            if (r.body() == null || r.header("Content-Encoding") != null) {

                return c.proceed(r);

            }

            Request re = r.newBuilder().header("Content-Encoding", "gzip").method(r.method(), y(r.body())).build();

            return c.proceed(re);

        }

        private RequestBody y(final RequestBody w) {

            return new RequestBody() {

                @Override
                public MediaType contentType() {

                    return w.contentType();

                }

                @Override
                public long contentLength() {

                    return -1;

                }

                @Override
                public void writeTo(BufferedSink sink) throws IOException {

                    BufferedSink z = Okio.buffer(new GzipSink(sink));

                    w.writeTo(z);

                    z.close();

                }

            };

        }

    }

    public static abstract class OnStartEndCreateDialog<D extends Dialog> {

        ProgressDialog d = createProgressDialog();

        private Asy a;

        void i(Asy s) {

            a = s;

        }

        public abstract void show(D dialog) throws Exception;

        public abstract void dismiss(D dialog) throws Exception;

        public abstract D create(Context context) throws Exception;

        public ProgressDialog createProgressDialog() {

            return new ProgressDialog<D>() {

                @Override
                public void show(D dialog) {

                    try {

                        OnStartEndCreateDialog.this.show(dialog);

                    } catch (Exception e1) {
                    }

                }

                @Override
                public void dismiss(D dialog) {

                    try {

                        OnStartEndCreateDialog.this.dismiss(dialog);

                    } catch (Exception e1) {
                    }

                }

                @Override
                public D create(Context context) {

                    try {

                        return OnStartEndCreateDialog.this.create(context);

                    } catch (Exception e1) {

                        return null;

                    }

                }

                @Override
                public void progress(D dialog, long total, long current, int percentage) {
                }

            };

        }

    }

    public interface ProgressDialog<D extends Dialog> {

        void show(D dialog) throws Exception;

        void dismiss(D dialog) throws Exception;

        D create(Context context) throws Exception;

        void progress(D dialog, long total, long current, int percentage) throws Exception;

    }

    private static class h {

        private static final Http a = new Http();

    }

}

